/*
 * Predicate.java
 */
package strips;

import java.util.ArrayDeque;

/**
 *
 * @author mire
 */
public class Predicate implements Goal {

    protected String name;
    protected int arity;
    protected ArrayDeque<Block> atributes;

    public Predicate(String name, ArrayDeque<Block> atributes) {
        this.name = correctName(name);
        this.arity = atributes.size();
        this.atributes = atributes;
    }

    public Predicate(String name) {
        this.name = correctName(name);
        this.atributes = new ArrayDeque<Block>();
    }

    public static String correctName(String inName) {
        if (inName.equalsIgnoreCase(on)) {
            return on;
        }
        if (inName.equalsIgnoreCase(onTable)) {
            return onTable;
        }
        if (inName.equalsIgnoreCase(clear)) {
            return clear;
        }
        if (inName.equalsIgnoreCase(holding)) {
            return holding;
        }
        if (inName.equalsIgnoreCase(armEmpty)) {
            return armEmpty;
        }
        if (inName.equalsIgnoreCase(black)) {
            return black;
        }
        if (inName.equalsIgnoreCase(white)) {
            return white;
        }
        return inName;
    }

    public String getName() {
        return name;
    }

    public ArrayDeque<Block> getAtributes() {
        return atributes;
    }

    public void setAtributes(ArrayDeque<Block> atributes) {
        this.atributes = atributes;
    }

    @Override
    public String toString() {
        String ret = name;
        if (arity != 0) {
            ret += "(" + atributes.peekFirst();
            if (arity == 2) {
                ret += "," + atributes.peekLast().toString();
            }
            ret += ")";
        }
        return ret;
    }

    public int getArity() {
        return arity;
    }
    //dohvata akciju koja je potrebna da bi se ispunio predikat

    public Action getAction(boolean loopdetected) {
        if (arity == 2) {
            //On -> stack
            return new Action(stack, atributes.clone());
        }
        if (arity == 1) {
            //OnTable -> putdown
            if (name.equals(onTable)) {
                return new Action(putdown, atributes.clone());
            }

            //Clear -> unstack
            if (name.equals(clear)) {
                ArrayDeque<Block> atr = atributes.clone();
                atr.addFirst(new Block());
                return new Action(unstack, atr);
            }

            //Holding -> unstack || pickup
            if (name.equals(holding)) {
                if (loopdetected) {
                    ArrayDeque<Block> atr = atributes.clone();
                    atr.addLast(new Block());
                    return new Action(unstack, atr);
                } else {
                    return new Action(pickup, atributes);
                }
            }

            //Black -> assimilate
            if (name.equals(black)) {
                ArrayDeque<Block> atr = atributes.clone();
                atr.addFirst(new Block());
                return new Action(assimilate, atr);
            }
        }
        if (arity == 0) {
            //ArmEmpty -> stack || putdown
            if (name.equals(armEmpty)) {
                ArrayDeque<Block> atr = atributes.clone();
                atr.add(new Block());
                if (loopdetected) {
                    return new Action(stack, atr);
                } else {
                    return new Action(putdown, atr);
                }
            }
        }
        return null;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Predicate other = (Predicate) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        if (this.arity != other.arity) {
            return false;
        }
        if (this.atributes != other.atributes && (this.atributes == null || other.atributes == null))
            return false;

        if (this.atributes != other.atributes && arity >= 1) {
            if (!this.atributes.peek().equals(other.atributes.peek())) {
                return false;
            }
        }
        if (this.atributes != other.atributes && arity == 2) {
            if (!this.atributes.peekLast().equals(other.atributes.peekLast())) {
                return false;
            }
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 73 * hash + (this.name != null ? this.name.hashCode() : 0);
        hash = 73 * hash + this.arity;
        hash = 73 * hash + (this.atributes != null ? this.atributes.hashCode() : 0);
        return hash;
    }
}
